package apis

import (
	"bytes"
	"compress/gzip"
	cryptoRand "crypto/rand"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/dchest/captcha"
	"io"
	"log"
	"math/big"
	mathRand "math/rand"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	GetDataMap     = map[string]*sync.Mutex{}
	GetDataMapLock = &sync.Mutex{}
)


/*获取复杂的随机数,数字和字母的组合
 * c > 2 数字的个数和字母的个数随机分配
 * n 数字的个数
 * l 字母的个数
 */
func GetComplexRandom(c, n, l int) string {
	if c < 2 && (n < 1 || l < 1) {
		return "--"
	}
	r := mathRand.New(mathRand.NewSource(time.Now().UnixNano()))
	myCommonMethod := func(flag bool) int {
		if flag {
			return r.Intn(c-1) + 1
		} else {
			return r.Intn(c)
		}
	}
	if c >= 2 {
		n = myCommonMethod(true)
		l = c - n
	} else {
		c = l + n
	}
	value := GetRandom(n) + GetLetterRandom(l)
	var array = strings.Split(value, "")
	for i := 0; i < c/2; i++ {
		r1 := myCommonMethod(false)
		r2 := myCommonMethod(false)
		o := array[r1]
		array[r1] = array[r2]
		array[r2] = o
	}
	return strings.Join(array, "")
}

//获取随机数
func GetRandom(n int) string {
	var idChars = []byte("0123456789")
	b := captcha.RandomDigits(n)
	for i, c := range b {
		b[i] = idChars[c]
	}
	return string(b)
}

//获取复杂的随机数
func GetLetterRandom(length int, flag ...bool) string {
	var idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
	var mod byte = 52
	if len(flag) > 0 && flag[0] {
		idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
		mod = 26
	}
	b := make([]byte, length)
	maxrb := byte(256 - (256 % int(mod)))
	i := 0
EXIT:
	for {
		r := make([]byte, length+(length/4))
		if _, err := io.ReadFull(cryptoRand.Reader, r); err != nil {
			panic("captcha: error reading random source: " + err.Error())
		}
		for _, c := range r {
			if c > maxrb {
				continue
			}
			b[i] = c % mod
			i++
			if i == length {
				break EXIT
			}
		}
	}
	for i, c := range b {
		b[i] = idChars[c]
	}
	return string(b)
}

func WriteJSON(w http.ResponseWriter, data interface{}) {
	w.Header().Set("Accept-Charset", "utf-8")
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Content-Encoding", "gzip")
	gz := gzip.NewWriter(w)
	defer gz.Close()
	err := json.NewEncoder(gz).Encode(data)
	if err != nil {
		log.Println("writejson err", err.Error())
	}
}

/**
加解密
	数据结构
	密文+sha32校验
*/
//
type SimpleEncrypt struct {
	Key string //加解密用到的key(加密key索引)+
}

//加密String
func (s *SimpleEncrypt) EncodeString(str string) string {
	data := []byte(str)
	s.doEncode(data)
	return base64.StdEncoding.EncodeToString(data)
}

//加密String,ByCheck
func (s *SimpleEncrypt) EncodeStringByCheck(str string) string {
	data := []byte(str)
	s.doEncode(data)
	v := s.calaCheckCode(data)
	data = append(data, v...)
	return base64.StdEncoding.EncodeToString(data)
}

//
func (s *SimpleEncrypt) Encode2Hex(str string) string {
	data := []byte(str)
	s.doEncode(data)
	return hex.EncodeToString(data)
}
func (s *SimpleEncrypt) Encode2HexByCheck(str string) string {
	data := []byte(str)
	s.doEncode(data)
	v := s.calaCheckCode(data)
	data = append(data, v...)
	return hex.EncodeToString(data)
}

//解密String
func (s *SimpleEncrypt) DecodeString(str string) string {
	data, _ := base64.StdEncoding.DecodeString(str)
	s.doEncode(data)
	return string(data)
}

//解密String,ByCheck
func (s *SimpleEncrypt) DecodeStringByCheck(str string) string {
	data, _ := base64.StdEncoding.DecodeString(str)
	if len(data) < 2 || !s.verify(data) {
		return ""
	}
	data = data[:len(data)-2]
	s.doEncode(data)
	return string(data)
}

//
func (s *SimpleEncrypt) Decode4Hex(str string) string {
	data, _ := hex.DecodeString(str)
	s.doEncode(data)
	return string(data)
}
func (s *SimpleEncrypt) Decode4HexByCheck(str string) string {
	data, _ := hex.DecodeString(str)
	if len(data) < 2 || !s.verify(data) {
		return ""
	}
	data = data[:len(data)-2]
	s.doEncode(data)
	return string(data)
}

//加密
func (s *SimpleEncrypt) Encode(data []byte) {
	s.doEncode(data)

}

func (s *SimpleEncrypt) EncodeByCheck(data []byte) {
	s.doEncode(data)
	v := s.calaCheckCode(data)
	data = append(data, v...)
}

//解密
func (s *SimpleEncrypt) Decode(data []byte) {
	s.doEncode(data)
}

//解密
func (s *SimpleEncrypt) DecodeByCheck(data []byte) {
	if len(data) < 2 || !s.verify(data) {
		data = []byte{}
		return
	}
	s.doEncode(data)
}

func (s *SimpleEncrypt) doEncode(bs []byte) {
	tmp := []byte(s.Key)
THEFOR:
	for i := 0; i < len(bs); {
		for j := 0; j < len(tmp); j, i = j+1, i+1 {
			if i >= len(bs) {
				break THEFOR
			}
			bs[i] = bs[i] ^ tmp[j]
		}
	}
}

//计算检验和
func (s *SimpleEncrypt) calaCheckCode(src []byte) []byte {
	check := 0
	for i := 0; i < len(src); i++ {
		check += int(src[i])
	}
	return []byte{byte((check >> 8) & 0xff), byte(check & 0xff)}
}

//验证数据有效性
func (s *SimpleEncrypt) verify(src []byte) bool {
	v := s.calaCheckCode(src[:len(src)-2])
	return bytes.Equal(v, src[len(src)-2:])
}

func Int64All(num interface{}) int64 {
	if i, ok := num.(int64); ok {
		return int64(i)
	} else if i0, ok0 := num.(int32); ok0 {
		return int64(i0)
	} else if i1, ok1 := num.(float64); ok1 {
		return int64(i1)
	} else if i2, ok2 := num.(int); ok2 {
		return int64(i2)
	} else if i3, ok3 := num.(float32); ok3 {
		return int64(i3)
	} else if i4, ok4 := num.(string); ok4 {
		i64, _ := strconv.ParseInt(i4, 10, 64)
		//in, _ := strconv.Atoi(i4)
		return i64
	} else if i5, ok5 := num.(int16); ok5 {
		return int64(i5)
	} else if i6, ok6 := num.(int8); ok6 {
		return int64(i6)
	} else if i7, ok7 := num.(*big.Int); ok7 {
		in, _ := strconv.ParseInt(fmt.Sprint(i7), 10, 64)
		return int64(in)
	} else if i8, ok8 := num.(*big.Float); ok8 {
		in, _ := strconv.ParseInt(fmt.Sprint(i8), 10, 64)
		return int64(in)
	} else {
		return 0
	}
}

func Float64All(num interface{}) float64 {
	if i, ok := num.(float64); ok {
		return float64(i)
	} else if i0, ok0 := num.(int32); ok0 {
		return float64(i0)
	} else if i1, ok1 := num.(int64); ok1 {
		return float64(i1)
	} else if i2, ok2 := num.(int); ok2 {
		return float64(i2)
	} else if i3, ok3 := num.(float32); ok3 {
		return float64(i3)
	} else if i4, ok4 := num.(string); ok4 {
		in, _ := strconv.ParseFloat(i4, 64)
		return in
	} else if i5, ok5 := num.(int16); ok5 {
		return float64(i5)
	} else if i6, ok6 := num.(int8); ok6 {
		return float64(i6)
	} else if i6, ok6 := num.(uint); ok6 {
		return float64(i6)
	} else if i6, ok6 := num.(uint8); ok6 {
		return float64(i6)
	} else if i6, ok6 := num.(uint16); ok6 {
		return float64(i6)
	} else if i6, ok6 := num.(uint32); ok6 {
		return float64(i6)
	} else if i6, ok6 := num.(uint64); ok6 {
		return float64(i6)
	} else if i7, ok7 := num.(*big.Float); ok7 {
		in, _ := strconv.ParseFloat(fmt.Sprint(i7), 64)
		return float64(in)
	} else if i8, ok8 := num.(*big.Int); ok8 {
		in, _ := strconv.ParseFloat(fmt.Sprint(i8), 64)
		return float64(in)
	} else {
		return 0
	}
}
func GetDayMinMax(t time.Time) (int64, int64) {
	min := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local).Unix()
	return min, min + 86400
}